package com.guosen.zebra.framework.starter.sso.service.impl;


import com.guosen.zebra.framework.starter.sso.constant.SsoConstant;
import com.guosen.zebra.framework.starter.sso.dto.EacResponse;
import com.guosen.zebra.framework.starter.sso.model.IasRequest;
import com.guosen.zebra.framework.starter.sso.properties.SsoProperties;
import com.guosen.zebra.framework.starter.sso.service.SsoCallBackService;
import com.guosen.zebra.framework.starter.sso.service.SsoService;
import com.guosen.zebra.framework.starter.sso.service.SsoSupportService;
import com.guosen.zebra.framework.starter.sso.utils.CookieUtils;
import com.guosen.zebra.framework.starter.sso.utils.EACValidateUtils;
import com.guosen.zebra.framework.starter.sso.utils.TimeUtils;
import com.guosen.zebra.framework.starter.sso.vo.SsoLoginVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.servlet.function.ServerRequest;
import org.springframework.web.servlet.function.ServerResponse;

import javax.servlet.http.Cookie;
import java.util.Optional;

@Slf4j
public class SsoServiceImpl implements SsoService {

    private final SsoProperties ssoProperties;
    private final SsoCallBackService ssoCallBackService;
    private final SsoSupportService ssoSupportService;

    public SsoServiceImpl(SsoProperties ssoProperties, SsoCallBackService ssoCallBackService, SsoSupportService ssoSupportService) {
        this.ssoProperties = ssoProperties;
        this.ssoCallBackService = ssoCallBackService;
        this.ssoSupportService = ssoSupportService;
    }

    @Override
    public String submitFormToSsoPage(String returnUrl, ServerRequest request, ServerResponse.BodyBuilder response) {
        String timeStamp = TimeUtils.timeStamp();
        IasRequest iasRequest = buildIasRequest(timeStamp);
        try {
            String authenticator =  EACValidateUtils.generateAuthenticator(iasRequest);
            SsoLoginVO ssoLoginVO = buildSsoLoginVO(timeStamp, authenticator);
            setReturnUrlCookie(returnUrl, response);
            return ssoSupportService.autoPostLoginPage(ssoLoginVO, request);
        } catch (Exception e) {
            log.error("Failed to create authenticator, message:{}", e.getMessage(), e);
            return ssoSupportService.errorPage(e.getMessage(), request);
        }
    }

    @Override
    public String ssoReturn(ServerRequest request, ServerResponse.BodyBuilder response, EacResponse eacResponse) {
        return handle(eacResponse, request, response);
    }

    private String handle(EacResponse eacResponse, ServerRequest request, ServerResponse.BodyBuilder response) {
        // sso登陆验证成功后回调, target为null表示调用成功
        String target = handleLoginSuccess(request, response, eacResponse);
        if (StringUtils.isEmpty(target)) {
            // 获取登录验证通过后的重定向url
            target = retrieveRedirectPage(request);
        }
        return target;
    }

    private IasRequest buildIasRequest(String timeStamp) {
        return IasRequest.builder()
                .iasId(ssoProperties.getIasId())
                .iasKey(ssoProperties.getIasKey())
                .returnUrl(ssoProperties.getBaseUrl() + ssoProperties.getSsoReturnPath())
                .timeStamp(timeStamp)
                .build();
    }

    private SsoLoginVO buildSsoLoginVO(String timeStamp, String authenticator ) {
        return SsoLoginVO.builder()
                .eacAddress(ssoProperties.getEacAddress())
                .iasId(ssoProperties.getIasId())
                .timeStamp(timeStamp)
                .returnUrl(ssoProperties.getBaseUrl() + ssoProperties.getSsoReturnPath())
                .ssoSignature(authenticator)
                .build();
    }

    private String handleLoginSuccess(ServerRequest request, ServerResponse.BodyBuilder response, EacResponse eacResponse) {
        try {
            return ssoCallBackService.handleLoginSuccess(request, response, eacResponse);
        } catch (Exception e) {
            log.error("ssoCallBackService afterLoginSuccess failed, message:{}", e.getMessage(), e);
            return ssoSupportService.errorPage(e.getMessage(), request);
        }
    }

    private String retrieveRedirectPage(ServerRequest request) {
        Cookie returnURLCookie = CookieUtils.getCookieByName(request, SsoConstant.RETURN_URL);
        return ssoSupportService.redirectPage(Optional.ofNullable(returnURLCookie).map(Cookie::getValue).orElse(""));
    }

    private void setReturnUrlCookie(String returnUrl, ServerResponse.BodyBuilder response) {
        if (StringUtils.isNotEmpty(returnUrl)) {
            Cookie ssoRetUrl = new Cookie(SsoConstant.RETURN_URL, returnUrl);
            ssoRetUrl.setPath("/");
            response.cookie(ssoRetUrl);
        }
    }
}
